﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace Utility
{
    public static class Security 
    {
        public static string GetMD5(string data)
        {
            string cl = data;
            string pwd = "";
            MD5 md5 = MD5.Create();//实例化一个md5对像 
            // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　 
            byte[] s = md5.ComputeHash(Encoding.Default.GetBytes(cl));
            // 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得 
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符 
                pwd = pwd + s[i].ToString("X2");
            }
            return pwd;
        }


        public static string GetSHA1(string data)
        {
            string cl = data;
            string pwd = "";
            SHA1 sha1 = SHA1.Create();//实例化一个SHA1对像 
            // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　 
            byte[] s = sha1.ComputeHash(Encoding.Default.GetBytes(cl));
            // 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得 
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符 
                pwd = pwd + s[i].ToString("X2");
            }
            return pwd;
        }

        /// <summary>累加和校验
        /// </summary>
        /// <param name="CheckData"></param>
        /// <returns></returns>
        static public string CheckSum(string CheckData)
        {
            //从帧起始符开始到校验码之前的所有各字节的和模256的余。即各字节二进制算术和，不计超过256的溢出值。

            if ((CheckData.Length % 2) != 0)
                return "";
            int Sum = 0;
            try
            {
                for (int i = 0; i < CheckData.Length; i = i + 2)
                {
                    Sum = Sum + Convert.ToInt32(CheckData.Substring(i, 2), 16);
                }

                string S = Sum.ToString("X");

                if (S.Length < 2)
                {
                    return S.PadLeft(2, '0');
                }
                else
                {
                    return S.Substring(S.Length - 2, 2);
                }
            }
            catch
            {
                return "";
            }
        }

        static public string ByteToStr(byte[] data)
        {
            string ret = "";
            for (int i = 0; i < data.Length; i++)
            {
                ret += data[i].ToString("X2");
            }
            return ret;
        }

        static public byte[] StrToByte(string data)
        {
            byte[] bt = new byte[data.Length / 2];
            for (int i = 0; i < data.Length / 2; i++)
            {
                bt[i] = Convert.ToByte(data.Substring(i * 2, 2), 16);
            }
            return bt;
        }

        /// <summary>
        /// 计算CRC-16
        /// </summary>
        /// <param name="data"></param>
        /// <returns>低位在前</returns>
        static public string CRC_16(string data)
        {
            if ((data.Length % 2) != 0) { throw new Exception("参数\"data\"长度不合法"); }
            byte[] tmp = StrToByte(data);

            /*
            1、预置16位寄存器为十六进制FFFF（即全为1）。称此寄存器为CRC寄存器； 
            2、把第一个8位数据与16位CRC寄存器的低位相异或，把结果放于CRC寄存器； 
            3、把寄存器的内容右移一位(朝低位)，用0填补最高位，检查最低位； 
            4、如果最低位为0：重复第3步(再次移位); 如果最低位为1：CRC寄存器与多项式A001（1010 0000 0000 0001）进行异或； 
            5、重复步骤3和4，直到右移8次，这样整个8位数据全部进行了处理； 
            6、重复步骤2到步骤5，进行下一个8位数据的处理； 
            7、最后得到的CRC寄存器即为CRC码。
            */
            UInt16 CRCREG = (UInt16)0xffff;
            for (int i = 0; i < tmp.Length; i++)
            {
                CRCREG = (UInt16)(CRCREG ^ (UInt16)tmp[i]);//<< 8;
                for (int j = 0; j < 8; j++)
                {
                    UInt16 CRCtmp = (UInt16)(CRCREG & (UInt16)0x0001);
                    CRCREG = (UInt16)(CRCREG >> (UInt16)1);
                    if (CRCtmp == (UInt16)1)
                    {
                        CRCREG = (UInt16)(CRCREG ^ (UInt16)0xA001);
                    }
                }
            }

            string strtmp = CRCREG.ToString("X4");

            return strtmp.Substring(2, 2) + strtmp.Substring(0, 2);
            //return strtmp;
        }

        /// <summary>
        /// 计算CRC-16
        /// </summary>
        /// <param name="data"></param>
        /// <returns>低位在前</returns>
        static public UInt16 CRC_16(byte[] data)
        {
            byte[] tmp = data;

            /*
            1、预置16位寄存器为十六进制FFFF（即全为1）。称此寄存器为CRC寄存器； 
            2、把第一个8位数据与16位CRC寄存器的低位相异或，把结果放于CRC寄存器； 
            3、把寄存器的内容右移一位(朝低位)，用0填补最高位，检查最低位； 
            4、如果最低位为0：重复第3步(再次移位); 如果最低位为1：CRC寄存器与多项式A001（1010 0000 0000 0001）进行异或； 
            5、重复步骤3和4，直到右移8次，这样整个8位数据全部进行了处理； 
            6、重复步骤2到步骤5，进行下一个8位数据的处理； 
            7、最后得到的CRC寄存器即为CRC码。
            */
            UInt16 CRCREG = (UInt16)0xffff;
            for (int i = 0; i < tmp.Length; i++)
            {
                CRCREG = (UInt16)(CRCREG ^ (UInt16)tmp[i]);//<< 8;
                for (int j = 0; j < 8; j++)
                {
                    UInt16 CRCtmp = (UInt16)(CRCREG & (UInt16)0x0001);
                    CRCREG = (UInt16)(CRCREG >> (UInt16)1);
                    if (CRCtmp == (UInt16)1)
                    {
                        CRCREG = (UInt16)(CRCREG ^ (UInt16)0xA001);
                    }
                }
            }

            byte H = (byte)((CRCREG >> 8) & 0x01);
            byte L = (byte)(CRCREG & 0x01);
            UInt16 ret = (UInt16)(((UInt16)L << 8) | (UInt16)H);
            return CRCREG;
        }


        static public string RandomDecString(int length)
        {
            string ret = "";
            string[] tab = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
            Random ra = new Random(unchecked((int)DateTime.Now.Ticks));
            for (int i = 0; i < length; i++)
            {
                ret += tab[ra.Next(0, 10)];
            }
            return ret;
        }

        static public string RandomHEXString(int length)
        {
            string ret = "";
            string[] tab = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
            Random ra = new Random(unchecked((int)DateTime.Now.Ticks));
            for (int i = 0; i < length; i++)
            {
                ret += tab[ra.Next(0, 16)];
            }
            return ret;
        }

        ///<summary>
        ///Base64加密
        ///</summary>
        ///<paramname="Message"></param>
        ///<returns></returns>
        public static string Base64Code(string message)
        {
            byte[] bytes = Encoding.Default.GetBytes(message);
            return Convert.ToBase64String(bytes);
        }
        ///<summary>
        ///Base64解密
        ///</summary>
        ///<paramname="Message"></param>
        ///<returns></returns>
        public static string Base64Decode(string message)
        {
            byte[] bytes = Convert.FromBase64String(message);
            return Encoding.Default.GetString(bytes);
        }

        /// <summary>
        /// 生成sign
        /// </summary>
        /// <param name="data">Method+ FactoryCode+ MeterTypeCode</param>
        /// <param name="data2">DataInput 未加密的JsonString</param>
        /// <returns></returns>
        public static string Sign(string data, string data2)
        {
            return GetMD5(GetMD5(data).ToUpper() + GetMD5(data2).ToLower()).ToLower();
        }

    }
}
